package com.JFapp.service.impl;

import com.JFapp.constants.SystemConstants;
import com.JFapp.domain.dto.AddArticleDto;
import com.JFapp.domain.dto.ArticleDto;
import com.JFapp.domain.dto.ArticleStatusDto;
import com.JFapp.domain.entity.Article;
import com.JFapp.domain.entity.ArticleTag;
import com.JFapp.domain.entity.Category;
import com.JFapp.domain.entity.ResponseResult;
import com.JFapp.domain.vo.ArticleDetailVo;
import com.JFapp.domain.vo.HotArticleVo;
import com.JFapp.domain.vo.PageVo;
import com.JFapp.domain.vo.articleListVo;
import com.JFapp.eumns.AppHttpCodeEnum;
import com.JFapp.exception.SystemException;
import com.JFapp.mapper.ArticleMapper;
import com.JFapp.service.ArticleService;
import com.JFapp.service.ArticleTagService;
import com.JFapp.service.CategoryService;
import com.JFapp.service.TagService;
import com.JFapp.utils.BeanCopyUtils;
import com.JFapp.utils.RedisCache;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * (Article)表服务实现类
 *
 * @author makejava
 * @since 2024-03-13 19:10:49
 */
@Service("articleService")
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements ArticleService {
    @Autowired
    private RedisCache redisCache;
    @Override
    public ResponseResult hotArticleList() {
        //查询热门文章，封装ResponseResult
        LambdaQueryWrapper<Article> queryWrapper=new LambdaQueryWrapper<>();
        //必须为正式文章
        queryWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL);
        //按照浏览量排序(降序)
        queryWrapper.orderByDesc(Article::getViewCount);
        //最多只查询10条,字面值处理
        Page<Article> page=new Page(SystemConstants.ARTICLE_DEFAULT_PAGE,SystemConstants.ARTICLE_PAGE_SIZE);
        page(page,queryWrapper);
        List<Article> articles=page.getRecords();
        List<HotArticleVo> vs= BeanCopyUtils.copyBeanList(articles,HotArticleVo.class);
        return ResponseResult.okResult(vs);
    }

    @Autowired
    private CategoryService categoryService;
    @Override
    public ResponseResult articleList(Integer pageNum, Integer pageSize, Long categoryId) {

        //查询条件
        LambdaQueryWrapper<Article> articles =new LambdaQueryWrapper<>();
        // ①是否有传回categoryId，有则要和传入相同
        articles.eq( Objects.nonNull(categoryId) && categoryId>0 ,Article::getCategoryId,categoryId);
        // ②要为正式发布文章
        articles.eq(Article::getStatus,SystemConstants.ARTICLE_STATUS_NORMAL);
        // ③对IsTop进行降序（置顶文章）
        articles.orderByDesc(Article::getIsTop);
        //分页查询
        Page<Article> page=new Page<>(pageNum,pageSize);
        page(page,articles);
        List<Article> articles1=page.getRecords();
        // 查询分类名称
        articles1.stream()
                .map(article -> article.setCategoryName(categoryService.getById(article.getCategoryId()).getName()))
                .collect(Collectors.toList());


        List<articleListVo> articleListVos  = BeanCopyUtils.copyBeanList(page.getRecords(), articleListVo.class);

        PageVo pageVo = new PageVo(articleListVos,page.getTotal());
        return ResponseResult.okResult(pageVo);
    }

    @Override
    public ResponseResult getArticleDetail(Long id) {
        //查询文章id获取文章正文
        Article article=getById(id);
        //从redis总获取浏览量
        Integer viewCount = redisCache.getCacheMapValue(SystemConstants.ARTICLE_VIEW_COUNT, id.toString());
        article.setViewCount(viewCount.longValue());
        //转化vo
        ArticleDetailVo articleDetailVo = BeanCopyUtils.copyBean(article, ArticleDetailVo.class);
        //根据分类ID查询对应分类名称
        Long categoryId = articleDetailVo.getCategoryId();
        Category category = categoryService.getById(categoryId);
        if (category!=null){
            articleDetailVo.setCategoryName(category.getName());
        }
        //封装响应返回
        return ResponseResult.okResult(articleDetailVo);
    }
    @Override
    public ResponseResult updateViewCount(Long id) {
        //更新redis中对应id的浏览量
        redisCache.incrementCacheMapValue(SystemConstants.ARTICLE_VIEW_COUNT,id.toString(),1);
        return ResponseResult.okResult();
    }

    @Autowired
    private ArticleTagService articleTagService;

    @Override
    @Transactional
    @ApiOperation("写文章")
    public ResponseResult writeArticle(ArticleDto articleDto) {
        //添加文章
        Article article = BeanCopyUtils.copyBean(articleDto, Article.class);

        //在articleServiceImpl下调用save保存到数据库
        save(article);

        //对articleDto中的tag进行流处理，将文章id和tagId传到articleTag中
        List<ArticleTag> articleTags = articleDto.getTags().stream()
                .map(tagId -> new ArticleTag(article.getId(), tagId))
                .collect(Collectors.toList());
        //添加文章和标签的关联
        articleTagService.saveBatch(articleTags);
        return ResponseResult.okResult();
}

    @Override
    public ResponseResult getArticleList(Integer pageNum, Integer pageSize) {
        LambdaQueryWrapper<Article> queryWrapper= new LambdaQueryWrapper<>();
        LambdaQueryWrapper<Article> wrapper = queryWrapper.orderByAsc(Article::getIsTop);
        Page<Article> page =new Page<>(pageNum,pageSize);
        page(page,wrapper);
        List<Article> articleList = page.getRecords();
        PageVo pageVo =new PageVo(articleList,page.getTotal());
        return ResponseResult.okResult(pageVo);
    }

    @Override
    public ResponseResult deleteArticle(Long id) {
        baseMapper.deleteById(id);
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult getDetailById(Long id) {

            //获取到文章 并转化成带tags类型
            Article article = getById(id);
            AddArticleDto addArticleDto = BeanCopyUtils.copyBean(article, AddArticleDto.class);

            //查询article-tag表中对应的tags
            LambdaQueryWrapper<ArticleTag> queryWrapper = new LambdaQueryWrapper<ArticleTag>();
            queryWrapper.select(ArticleTag::getTagId);
            queryWrapper.eq(ArticleTag::getArticleId, addArticleDto.getId());
            List<Long> tagList = articleTagService.list(queryWrapper)
                    .stream()
                    .map(ArticleTag::getTagId)
                    .collect(Collectors.toList());
            addArticleDto.setTags(tagList);
            return ResponseResult.okResult(addArticleDto);
    }

    @Override
    public ResponseResult updateArticle(ArticleDto articleDto) {
        Article article = BeanCopyUtils.copyBean(articleDto, Article.class);
        LambdaUpdateWrapper<Article> updateWrapper =new LambdaUpdateWrapper<>();
        LambdaUpdateWrapper<Article> wrapper = updateWrapper.eq(Article::getId, article.getId());
        update(article,wrapper);
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult updateArticleStatus(ArticleStatusDto articleStatusDto) {
        LambdaUpdateWrapper<Article> updateWrapper =new LambdaUpdateWrapper<>();
        LambdaUpdateWrapper<Article> wrapper = updateWrapper.set(Article::getStatus, articleStatusDto.getStatus()).eq(Article::getId, articleStatusDto.getId());
        update(wrapper);
        return ResponseResult.okResult();
    }

    @Scheduled(cron = "0 0/5 * * * ?") //每5分钟执行一次
    public void updateViewCount(){
        Map<String, Integer> map = redisCache.getCacheMap(SystemConstants.ARTICLE_VIEW_COUNT);
        Map<Long,Long> view=new HashMap<>();
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            view.put(Long.parseLong(entry.getKey()), Long.valueOf(entry.getValue()));
        }
        baseMapper.updateViewCount(view);
    }


}
